﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using SunrayEngine.Threading;

namespace SunrayEngine.Managers
{
    /// <summary>
    /// The SunRay Engine updater, managing its own thread system for all component update calls.
    /// </summary>
    public class UpdateManager
    {
        #region fields
        private MultiThreadInvoker workHandler; //The handler for all worker threads.
        private GameComponentCollection components; //Refed from the SRMain and handels all component updateing.
        private IEnumerable<GameComponent> updateabelComponents; //Components that can be updated.
        #endregion

        #region properties
        /// <summary>
        /// Returns the ammount of currently active threads.
        /// </summary>
        public int ActiveThreads { get { return workHandler.ActiveThreads; } }
        #endregion

        #region initialization
        public UpdateManager(Game game, int workerThreads)
        {
            workHandler = new MultiThreadInvoker(workerThreads);

            components = game.Components;
            getUpdateabelComponents();

            components.ComponentAdded += (s, e) => { getUpdateabelComponents(); };
            components.ComponentRemoved += (s, e) => { getUpdateabelComponents(); };
        }
        #endregion

        #region methods
        public void DisposeThreads()
        {
            workHandler.Dispose();
        }

        /// <summary>
        /// Updates the manager and with it all game components.
        /// If you use this remove base.Update(GameTime) from the main class of the game.
        /// </summary>
        /// <param name="gameTime"></param>
        public void Update(GameTime gameTime)
        {
            //Hijack the games components and update them in the work handler.
            foreach (var component in updateabelComponents)
                workHandler.Queue(new Action(() => { component.Update(gameTime); }));
        }

        private void getUpdateabelComponents()
        {
            //Get a collection of the updateabel components from the Component collection.
            updateabelComponents = (from c in components where c is GameComponent select c as GameComponent);
        }
        #endregion
    }
}